package main

import (
	"fmt"
	"runtime"
	"time"
)

// for channel, although channel can also notify many nested goroutines to exit,
// channel is not thread-safe, while context is thread-safe

func monitor2(ch <-chan bool, index int) {
	for {
		select {
		case v := <-ch:
			fmt.Printf("monitor2: %v, the received channel value is: %v, ending\n", index, v)
			return
		default:
			fmt.Printf("monitor2: %v in progress...\n", index)
			time.Sleep(2 * time.Second)
		}
	}
}

func monitor1(ch <-chan bool, index int) {
	for {
		go monitor2(ch, index)
		select {
		// this branch is only reached when the ch is closed, or when data is sent (either true or false).
		case v := <-ch:
			fmt.Printf("monitor1: %v, the received channel value is: %v, ending\n", index, v)
			return
		default:
			fmt.Printf("monitor1: %v in progress...\n", index)
			time.Sleep(2 * time.Second)
		}
	}
}

func main() {
	var stopSingal chan bool = make(chan bool)
	for i := 1; i <= 5; i++ {
		go monitor1(stopSingal, i)
	}

	time.Sleep(1 * time.Second)

	// close all goroutines
	close(stopSingal)

	time.Sleep(10 * time.Second)

	fmt.Println(runtime.NumGoroutine())
	fmt.Println("main program exit!!")
}
